package eu.irreality.dai.ui.simascii;

import java.awt.Color;
import java.util.Iterator;
import java.util.StringTokenizer;

import eu.irreality.dai.ui.cell.DisplayPriorityComparator;
import eu.irreality.dai.ui.cell.DisplayableCharacter;
import eu.irreality.dai.ui.cell.DisplayableObject;
import eu.irreality.dai.ui.wrapper.Display;
import eu.irreality.dai.ui.wrapper.DisplayLayer;
import eu.irreality.dai.util.Debug;
import eu.irreality.dai.util.SortedList;
import eu.irreality.dai.world.level.Level;

public class SimulatedAsciiDisplayLayer extends DisplayLayer
{

    // point where the viewport will be centered, if scrolling is activated
    private int cameraPointRow;

    private int cameraPointCol;

    private boolean scroll = false; // scrolling activated?

    private SortedList[][] grid;
    private boolean[][] seen; // for levels and such

    private int viewCenterRow;
    private int viewCenterCol;

    public SimulatedAsciiDisplayLayer(Display d, int firstRow, int firstCol,
	    int rows, int cols)
    {
	super(d, firstRow, firstCol, rows, cols);
	viewCenterRow = rows / 2;
	viewCenterCol = cols / 2;
	initGrid();
    }

    public void initGrid()
    {
	int rows = getRows();
	int cols = getCols();
	Debug.println("size " + rows + "," + cols);
	grid = new SortedList[rows][cols];
	DisplayPriorityComparator dpc = new DisplayPriorityComparator();
	for (int i = 0; i < rows; i++)
	    for (int j = 0; j < cols; j++)
		grid[i][j] = new SortedList<DisplayableObject>(dpc);
    }

    public void addContent(int row, int col, DisplayableObject dObj)
    {
	SortedList<DisplayableObject> theList = grid[row][col];
	theList.add(dObj);
    }

    // current position in which to draw text
    private int curRow = 0;
    private int curCol = 0;

    private void nextLine()
    {
	if (curRow >= getRows() - 1)
	    scrollUp();
	else
	    curRow++;
	curCol = 0;
    }

    public void appendText(String text, Color color)
    {
	StringTokenizer st = new StringTokenizer(text, " \t\n", true);
	while (st.hasMoreTokens())
	{
	    String theToken = st.nextToken();
	    if (theToken.contains(" ") || theToken.contains("\t")
		    || theToken.contains("\n"))
	    {
		// whitespace token
		// actually theToken should have length one. So, simplify.
		for (int i = 0; i < theToken.length(); i++)
		{
		    if (theToken.charAt(i) == '\n')
		    {
			nextLine();
		    }
		    if (theToken.charAt(i) == '\t')
		    {
			curCol = curCol / 10 * 10 + 10;
			if (curCol >= getCols())
			{
			    nextLine();
			}
		    }
		    if (theToken.charAt(i) == ' ')
		    {
			// if ( opaque ) clearCell(curRow,curCol);
			addContent(curRow, curCol, new DisplayableCharacter(
				' ', color));
			curCol++;
		    }
		}
	    } else
	    {
		if (curCol + theToken.length() < getCols())
		{
		    for (int i = 0; i < theToken.length(); i++)
		    {
			// if ( opaque ) clearCell(curRow,curCol);
			addContent(curRow, curCol, new DisplayableCharacter(
				theToken.charAt(i), color));
			curCol++;
			if (curCol >= getCols())
			{
			    nextLine();
			}
		    }
		} else if (theToken.length() <= getCols())
		{
		    nextLine();
		    for (int i = 0; i < theToken.length(); i++)
		    {
			// if ( opaque ) clearCell(curRow,curCol);
			addContent(curRow, curCol, new DisplayableCharacter(
				theToken.charAt(i), color));
			curCol++;
		    }
		} else
		{
		    // v. long word
		    for (int i = 0; i < theToken.length(); i++)
		    {
			// if ( opaque ) clearCell(curRow,curCol);
			addContent(curRow, curCol, new DisplayableCharacter(
				theToken.charAt(i), color));
			curCol++;
			if (curCol >= getCols())
			{
			    nextLine();
			}
		    }
		}
	    }
	}
    }

    /**
     * Used to scroll the text up one position in a text layer.
     */
    private void scrollUp()
    {
	for (int r = 0; r < getRows() - 1; r++)
	{
	    // copy contents of row r+1 into row r
	    for (int c = 0; c < getCols(); c++)
	    {
		grid[r][c] = (SortedList<DisplayableObject>) grid[r + 1][c]
			.clone();
	    }
	}
	// delete last row
	assert getRows() > 0 : "rows must be > 0 to use scrollUp()";
	for (int c = 0; c < getCols(); c++)
	{
	    clearCell(getRows() - 1, c);
	}
    }

    /**
     * Useful for text layers, sets the content of this layer to be a
     * representation of the given string of text.
     * 
     * @param text
     */
    public void setText(String text, Color color, boolean opaque)
    {
	if (opaque)
	    clear();
	curRow = 0;
	curCol = 0;
	appendText(text, color);
    }

    public void setLevel(Level l)
    {
	this.grid = l.getGrid();
	this.seen = l.getSeen();
    }

    public void clear()
    {
	int rows = getRows();
	int cols = getCols();
	for (int i = 0; i < rows; i++)
	    for (int j = 0; j < cols; j++)
		grid[i][j].clear();
    }

    public void clearCell(int row, int col)
    {
	grid[row][col].clear();
    }

    public void setCameraPoint(int row, int col)
    {
	cameraPointRow = row;
	cameraPointCol = col;
    }

    private int translateRowForScrolling(int row)
    {
	if (scroll)
	    return getFirstRow() + row - cameraPointRow + viewCenterRow;
	else
	    return getFirstRow() + row;
    }

    private int translateColForScrolling(int col)
    {
	if (scroll)
	    return getFirstCol() + col - cameraPointCol + viewCenterCol;
	else
	    return getFirstCol() + col;
    }

    protected void drawGridToDisplay()
    {
	for (int i = 0; i < getRows(); i++)
	{
	    for (int j = 0; j < getCols(); j++)
	    {
		if (seen == null || seen[i][j])
		{
		    SortedList<DisplayableObject> dispObjs = grid[i][j];
		    for (Iterator<DisplayableObject> iter = dispObjs.iterator(); iter
			    .hasNext();)
		    {
			DisplayableObject dispObj = iter.next();
			((SimulatedAsciiDisplay) getDisplay()).drawToBuffer(
				translateRowForScrolling(i),
				translateColForScrolling(j), dispObj);
		    }
		}
	    }
	}

    }
}